﻿#ifndef GAME_H
#define GAME_H

#include "Game/GameCore_Thread.h"
#include "Game/Player.h"


#include "_Global/Sqlite/Sqlite.h"


#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QList>
#include <QQueue>
#include <QByteArray>
#include <QDebug>


#define WAIT_GAME_TERMINATE_TIME 5000


class TcpSocket;
class Game_Thread : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool netPlay READ netPlay) //当前正在考的 单词 信息(qml用)

    Q_PROPERTY(_ClientGameStatus clientGameStatus READ clientGameStatus WRITE setClientGameStatus NOTIFY clientGameStatusChanged)    //复习卡
    Q_PROPERTY(bool isMaster READ isMaster WRITE setMaster NOTIFY masterChanged)    //用户游戏状态

    Q_PROPERTY(QObjectList testList READ testList)



public:
    //游戏时状态
    struct _GameInfo
    {
        _ClientGameStatus m_ClientGameStatus;     //状态!!!
        qint32  m_nGroupId;      //用户加入的 房间
        bool    m_bIsMaster;          //是否是房主!!!

        _GameInfo()
        {
            m_ClientGameStatus = _ClientGameStatus::Game_Nothing;
            m_nGroupId = -1;
            m_bIsMaster = false;
        }
    }m_GameInfo;



//本类发出的信号
signals:
    //socket发送数据(主线程发送)
    void s_SendDataToServer(QByteArray data, quint8 outControlbyte);//发送数据


    void masterChanged(bool newValue);
    void clientGameStatusChanged(int newValue);


public:
    explicit Game_Thread(QObject *parent = nullptr);
    virtual ~Game_Thread()
    {
        TerminateGame(GameClientModel::Game_Status_Terminated, -1);
    }

    /*void quit(){}
    bool wait(int t){return 1;}
    void terminate(){}
    bool isRunning(){return true;}
    bool start(){return true;}*/

//重载游戏框架
public:
    virtual int InitOnce() Q_DECL_OVERRIDE   //进行初始化(仅1次)
    {
        int ret = GameCore_Thread::InitOnce();
        m_pGameClientModel->m_bRunAtServer = false;
        return ret;
    }
    virtual int InitOnceInThread() Q_DECL_OVERRIDE //线程中初始化(1次)
    {
        return GameCore_Thread::InitOnceInThread();
    }
    virtual int GameInit(int sr = -1) Q_DECL_OVERRIDE;
    virtual int GameOver() Q_DECL_OVERRIDE
    {
        return GameCore_Thread::GameOver();
    }

    //强制结束游戏
    virtual int TerminateGame( GameClientModel::_GameStatus status = GameClientModel::Game_Status_Exit, int nCode = 0) Q_DECL_OVERRIDE
    {
        int ret = GameCore_Thread::TerminateGame(status, nCode);
        if(ret == 0)
            return ret;


        //m_mutexNet.tryLock();
        //m_mutexQuestion.tryLock();

        //getDataList();
        //pMutexNet->lock();
        m_Producer.comingNetDataSemaphore();
        //pMutexNet->unlock();
        //pMutexData->tryLock();
        //releaseDataList();
        //questionFinished();

        sl_UserActionFinished();

        quit();
        if(!wait(WAIT_GAME_TERMINATE_TIME))  //返回true:线程已经退出
        {
            terminate();
        }
        //if(bGameIsRunning)
        //    emit m_pGameClientModel->s_GameOver(status ,nCode);
        return ret;
    }

protected:
    virtual GameClientModel::_GameStatus CheckGameOver() Q_DECL_OVERRIDE
    {
        GameClientModel::_GameStatus status = GameCore_Thread::CheckGameOver();
        /*
        if(ret != Game_Status_Continue)
        {
            //exit();quit();
        }*/
        return status;
    }

    qint16 Random()
    {
        if(m_bNetPlay)
        {
            if(m_queueFakeRandom.count() > 0)
                return m_queueFakeRandom.dequeue();
            else
            {
                Critical(_T("[!Game]Random number is empty!!!"));
            }
        }
        else
            return qrand();
    }


//UI游戏框架
public:
    //等待UI解锁进程
    virtual void WaitForUserAction() Q_DECL_OVERRIDE
    {
        //注意:
        //unlock状态下:unlock函数会出错;QWaitCondition::wait函数会出错
        //所以保持lock状态
        m_mutexUserAction.lock();
        if(m_pGameClientModel->gameStatus() != GameClientModel::Game_Status_Continue)
        {
            m_mutexUserAction.unlock();
            return;
        }
        m_waitForUserAction.wait(&m_mutexUserAction);
        m_mutexUserAction.unlock();
        //qDebug()<<"m_mutexUserAction lock1!!!";
        //m_mutexUserAction.tryLock();  //立即返回是否已锁定(肯定会锁定)
        //m_waitForNet.wait(&m_mutexUserAction);
    }

    /*
    virtual void WaitForNet() Q_DECL_OVERRIDE
    {
        qDebug()<<"m_mutexNet lock0!!!";
        m_mutexNet.lock();
        qDebug()<<"m_mutexNet lock1!!!";
    }*/

//qml信号槽
public slots:
    /*Q_INVOKABLE*/ virtual void sl_UserActionFinished() Q_DECL_OVERRIDE
    {
        //qDebug()<<"m_mutexUserAction unlock0!!!";
        //m_mutexUserAction.tryLock();    //防止多个数据包到来时多次unlock
        //m_mutexUserAction.unlock();
        m_mutexUserAction.lock();
        m_waitForUserAction.wakeAll();
        m_mutexUserAction.unlock();
        //qDebug()<<"m_mutexUserAction unlock1!!!";
        //m_waitForUserAction.wakeAll();
        //qDebug()<<"wakeALL!!";
    }
    /*
    virtual void netFinished() Q_DECL_OVERRIDE
    {
        //qDebug() << "netFinished线程:" << QThread::currentThreadId();
        //qDebug()<<"m_mutexNet tryLock unlock0!!!" <<QThread::currentThreadId();;
        m_mutexNet.tryLock();    //防止多个数据包到来时多次unlock
        m_mutexNet.unlock();
        //qDebug()<<"m_mutexNet tryLock unlock1!!!" << QThread::currentThreadId();;
        //m_waitForNet.wakeAll();
        //qDebug()<<"wakeALL!!";
    }*/






//重载游戏逻辑



//游戏其他函数
public slots:
    //游戏线程提交给主线程 发送数据
    void SendDataToServer(QByteArray& data, quint8 outControlbyte = 0x20);

    //qml调用,选择
    void sl_qml_UserChoice(QVariant param)
    {
        QVariantMap map = param.toMap();
        m_GameFightLogical.m_UserChoice.target = map.value("target").toInt();
        m_GameFightLogical.m_UserChoice.choiceAttack = map.value("choiceAttack").toInt();
        m_GameFightLogical.m_UserChoice.choiceDefence = map.value("choiceDefence").toInt();

        sl_UserActionFinished();
    }


    //qml调用,调试
    void sl_qml_DebugButton(int button, QVariant v);


//属性
public:
    bool netPlay() const
    {
        return m_bNetPlay;
    }


    _ClientGameStatus clientGameStatus() const
    {
        return m_GameInfo.m_ClientGameStatus;
    }

    void setClientGameStatus(_ClientGameStatus newValue)
    {
        if(m_GameInfo.m_ClientGameStatus != newValue)
        {
            m_GameInfo.m_ClientGameStatus = newValue;
            emit clientGameStatusChanged(newValue);
        }
    }

    bool isMaster() const
    {
        return m_GameInfo.m_bIsMaster;
    }

    void setMaster(bool newValue)
    {
        if(m_GameInfo.m_bIsMaster != newValue)
        {
            m_GameInfo.m_bIsMaster = newValue;
            emit masterChanged(newValue);
        }
    }


//测试
    QObjectList testList() const
    {
        return m_listTest;
    }

public:
//UI游戏框架
    //QWaitCondition需要已锁的QMutex才能wait,wait时会将QMutex unlock!!
    QWaitCondition  m_waitForUserAction;
    QMutex          m_mutexUserAction;
    //bool            m_bAction;      //是否可以Wake工作线程,其实也可以不用

    //QWaitCondition  m_waitForQuestion;
    //QWaitCondition  m_waitForNet;
    //QMutex          m_mutexQuestion;

//网络游戏框架
    ProducerModel   m_Producer;
    TcpSocket       *m_pGameSocket;
    QQueue<qint16>  m_queueFakeRandom;      //伪随机数



public:
//游戏数据:
    Sqlite          *m_pSqliteDB;           //配置(Manager赋值)

    QMap<qint32, _Player::PlayerInfo>  m_mapPlayerInfoCache;

//游戏配置
    bool            m_bNetPlay;


//测试
    QObjectList     m_listTest;
};

//Q_DECLARE_METATYPE(GameCore_Thread::_GameStatus)

#endif //GAME_H
